#include <stdio.h>
#include <stdlib.h>

#ifndef WIN32
#define _strdup strdup
#endif

typedef struct buffer_t
{
	char* name;
	int size;
	char data[4];
} buffer_t;

static buffer_t* read_to_buffer(const char *filename)
{
	FILE* f = fopen(filename, "rb");
	if (f == NULL) {
		return NULL;
	}
	/* get the file size. */
	fseek(f, 0, SEEK_END);
	int size = ftell(f);
	/* allocate enough heap memory. */
	buffer_t* buf = (buffer_t*)malloc(sizeof(buffer_t) + size + 1);
	if (buf == NULL) {
		fclose(f);
		return NULL;
	}
	buf->name = _strdup(filename);
	buf->data[size] = 0;
	/* set current position to the beginning of the file. */
	fseek(f, 0, SEEK_SET);
	buf->size = (int)fread(buf->data, 1, size, f);
	fclose(f);

	return buf;
}

static buffer_t* do_stdin_to_buffer(int end)
{
	int c;
	int size = 0;
	int buffer_size = 256;
	buffer_t* buf = (buffer_t*)malloc(sizeof(buffer_t) + buffer_size + 1);
	if (buf == NULL) {
		return NULL;
	}
	buf->name = NULL;
	buf->data[buffer_size] = 0;
	while ((c = getchar()) != end)
	{
		if (size >= buffer_size) {
			buffer_size *= 2;
			buf = (buffer_t*)realloc(buf, sizeof(buffer_t) + buffer_size + 1);
			if (buf == NULL) {
				return NULL;
			}
			buf->data[buffer_size] = 0;
		}
		buf->data[size++] = c;
	}
	buf->size = size;
	return buf;
}

static buffer_t* stdin_to_buffer()
{
	return do_stdin_to_buffer(EOF);
}

static buffer_t* stdin_line_to_buffer()
{
	return do_stdin_to_buffer('\n');
}

static void free_buffer(buffer_t* buf)
{
	if (buf == NULL)
		return;
	if (buf->name)
		free(buf->name);
	free(buf);
}